//
//  WebBrowserContentView.swift
//  App_Common_WebBrowser
//
//  Created by 蒋晨成 on 2022/1/19.
//

import Adaptor
import Base
import Foundation
import UIKit
import WebKit

class WebBrowserContentView: View {
    private weak var delegate: Delegate?

    private lazy var webView: WKWebView = {
        let configuration = WKWebViewConfiguration()
        configuration.websiteDataStore.httpCookieStore.add(self)
        let webView = WKWebView(
            frame: .zero,
            configuration: configuration
        )
        webView.backgroundColor = .systemBackground
        webView.uiDelegate = self
        webView.navigationDelegate = self
        webView.scrollView.delegate = self

        webViewObservations.append(webView.observe(\.url, options: [.new]) { [weak self] (view: WKWebView, change: NSKeyValueObservedChange<URL?>) in
            guard let self = self else { return }
            self.observe(webView: view, valueChanged: change)
        })
        webViewObservations.append(webView.observe(\.title, options: [.new]) { [weak self] (view: WKWebView, change: NSKeyValueObservedChange<String?>) in
            guard let self = self else { return }
            self.observe(webView: view, valueChanged: change)
        })
        webViewObservations.append(webView.observe(\.estimatedProgress, options: [.new]) { [weak self] (view: WKWebView, change: NSKeyValueObservedChange<Double>) in
            guard let self = self else { return }
            self.observe(webView: view, valueChanged: change)
        })
        webViewObservations.append(webView.observe(\.canGoBack, options: [.new]) { [weak self] (view: WKWebView, change: NSKeyValueObservedChange<Bool>) in
            guard let self = self else { return }
            self.observe(webView: view, valueChanged: change)
        })
        webViewObservations.append(webView.observe(\.canGoForward, options: [.new]) { [weak self] (view: WKWebView, change: NSKeyValueObservedChange<Bool>) in
            guard let self = self else { return }
            self.observe(webView: view, valueChanged: change)
        })
        return webView
    }()

    private lazy var progressBar: UIProgressView = .init(progressViewStyle: .bar)
        .x
        .tintColor(.label)
        .instance

    private lazy var webViewObservations = [NSKeyValueObservation]()

    init(frame: CGRect = .zero, delegate: Delegate?) {
        self.delegate = delegate
        super.init(frame: frame)
        setup()
    }

    private var webViewLastOffsetY: CGFloat = 0

    @available(*, unavailable)
    required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

private extension WebBrowserContentView {
    func setup() {
        webView.x.add(to: self).snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
        progressBar.x.add(to: self).snp.makeConstraints {
            $0.leading.trailing.equalToSuperview()
            $0.bottom.equalTo(self.snp.top)
        }
    }

    func observe(webView: WKWebView, valueChanged: NSKeyValueObservedChange<URL?>) {
        delegate?.contentView(self, webView: webView, urlDidChange: valueChanged.newValue as? URL)
    }

    func observe(webView: WKWebView, valueChanged: NSKeyValueObservedChange<String?>) {
        delegate?.contentView(self, webView: webView, titleDidChange: valueChanged.newValue as? String)
    }

    func observe(webView: WKWebView, valueChanged: NSKeyValueObservedChange<Double>) {
        delegate?.contentView(self, webView: webView, estimatedProgressDidChange: valueChanged.newValue ?? 0)
    }

    func observe(webView _: WKWebView, valueChanged _: NSKeyValueObservedChange<Bool>) {}
}

extension WebBrowserContentView {
    func load(url: URL) {
        let request = URLRequest(url: url)
        webView.load(request)
    }

    func set(progress: Float) {
        switch progress {
        case 1:
            progressBar.isHidden = true
            progressBar.setProgress(0, animated: false)
        case 0:
            progressBar.setProgress(progress, animated: false)
        default:
            progressBar.setProgress(progress, animated: true)
            progressBar.isHidden = false
        }
    }
}

extension WebBrowserContentView: WKUIDelegate {
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let alertController = UIAlertController(title: webView.url?.absoluteString, message: message, preferredStyle: .alert)
            .x
            .addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler() })
            .instance
        delegate?.contentView(self, webView: webView, showAlert: alertController)
    }
}

extension WebBrowserContentView: WKNavigationDelegate {
    #if DEBUG
        func webView(
            _: WKWebView,
            decidePolicyFor navigationAction: WKNavigationAction,
            preferences: WKWebpagePreferences,
            decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void
        ) {
            logger.info("\(navigationAction.request.url?.absoluteString ?? "no valid url")")
            decisionHandler(.allow, preferences)
        }
    #endif
}

extension WebBrowserContentView: UIScrollViewDelegate {
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        webViewLastOffsetY = scrollView.contentOffset.y
    }

    func scrollViewDidEndDragging(_: UIScrollView, willDecelerate _: Bool) {
//        let hide = scrollView.contentOffset.y > webViewLastOffsetY
//        layout(isToolBarHidden: hide)
    }
}

extension WebBrowserContentView: WKHTTPCookieStoreObserver {
    func cookiesDidChange(in _: WKHTTPCookieStore) {}
}

extension WebBrowserContentView {
    typealias DataSource = WebBrowserContentViewDataSource
    typealias Delegate = WebBrowserContentViewDelegate
}

protocol WebBrowserContentViewDataSource: AnyObject {}

protocol WebBrowserContentViewDelegate: AnyObject {
    func contentView(_ contentView: WebBrowserContentView, webView: WKWebView, urlDidChange url: URL?)
    func contentView(_ contentView: WebBrowserContentView, webView: WKWebView, titleDidChange title: String?)
    func contentView(_ contentView: WebBrowserContentView, webView: WKWebView, estimatedProgressDidChange estimatedProgress: Double)
    func contentView(_ contentView: WebBrowserContentView, webView: WKWebView, showAlert alertController: UIAlertController)
}
